/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2019-2021.
 * Description: This file contains driver APIs to the msi subsystem.
 * Author: xiaojiangfeng
 * Create: 2019-07-31
 */

#include <linux/msi.h>
#include <linux/hal/support_pci_spec.h>

static DEFINE_RWLOCK(arch_setup_lock);
static int (*default_arch_setup_msi_irq)(struct pci_dev *, struct msi_desc *);

int register_arch_setup_msi_irq(void *handler)
{
	if (!handler) {
		pr_err("fail to register arch_setup_msi_irq\n");
		return -ENOENT;
	}

	write_lock(&arch_setup_lock);
	default_arch_setup_msi_irq = handler;
	write_unlock(&arch_setup_lock);
	pr_info("success to register arch_setup_msi_irq %pS\n", handler);

	return 0;
}
EXPORT_SYMBOL_NS(register_arch_setup_msi_irq, HW_RTOS_NS);

int unregister_arch_setup_msi_irq(void)
{
	write_lock(&arch_setup_lock);
	default_arch_setup_msi_irq = NULL;
	write_unlock(&arch_setup_lock);
	pr_info("success to unregister arch_setup_msi_irq\n");

	return 0;
}
EXPORT_SYMBOL_NS(unregister_arch_setup_msi_irq, HW_RTOS_NS);

bool rtos_setup_msi_done(struct pci_dev *dev, struct msi_desc *desc)
{
	bool done = false;

	read_lock(&arch_setup_lock);

	if (default_arch_setup_msi_irq) {
		default_arch_setup_msi_irq(dev, desc);
		done = true;
	} else {
		done = false;
	}

	read_unlock(&arch_setup_lock);

	return done;
}

static DEFINE_RWLOCK(arch_teardown_lock);
static void (*default_arch_teardown_msi_irq)(unsigned int);

int register_arch_teardown_msi_irq(void *handler)
{
	if (!handler) {
		pr_err("fail to register arch_setup_msi_irq\n");
		return -ENOENT;
	}

	write_lock(&arch_teardown_lock);
	default_arch_teardown_msi_irq = handler;
	write_unlock(&arch_teardown_lock);
	pr_info("success to register arch_teardown_msi_irq %pS\n", handler);

	return 0;
}
EXPORT_SYMBOL_NS(register_arch_teardown_msi_irq, HW_RTOS_NS);

int unregister_arch_teardown_msi_irq(void)
{
	write_lock(&arch_teardown_lock);
	default_arch_teardown_msi_irq = NULL;
	write_unlock(&arch_teardown_lock);
	pr_info("success to unregister arch_teardown_msi_irq\n");

	return 0;
}
EXPORT_SYMBOL_NS(unregister_arch_teardown_msi_irq, HW_RTOS_NS);

bool rtos_teardown_msi_done(unsigned int irq)
{
	bool done = false;

	read_lock(&arch_teardown_lock);

	if (default_arch_teardown_msi_irq) {
		default_arch_teardown_msi_irq(irq);
		done = true;
	} else {
		done = false;
	}
	read_unlock(&arch_teardown_lock);

	return done;
}
